package com.webserver.http;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import static com.webserver.http.HttpContext.CR;
import static com.webserver.http.HttpContext.LF;
//也可以静态导入方法
import static com.webserver.http.HttpContext.getMimeType;

/**
 * 响应对象
 * 该类的每一个实例用于表示要给客户端发送的一个HTTP响应
 * 一个响应由三部分构成:状态行，响应头，响应正文。
 * 
 * @author pc
 *
 */
public class HttpResponse {
	//状态行相关信息
	private int statusCode = 200;//状态代码，默认值为200
	private String statusReason = "OK";//状态描述，默认值为OK
	
	//响应头相关信息
	private Map<String,String> headers = new HashMap<>();
	
	//响应正文相关信息
	private File entity;//正文对应的文件
	private byte[] content;//正文直接对应的字节
	
	private Socket socket;
	private OutputStream out;
	public HttpResponse(Socket socket) {
		try {
			this.socket = socket;
			out = socket.getOutputStream();
		} catch (Exception e) {
			e.printStackTrace();
		}		
	}
	
	/**
	 * 将当前响应对象内容以标准的HTTP响应格式发送给客户端
	 */
	public void flush() {
		try {
			//1发送状态行
			sendStatusLine();			
			//2发送响应头
			sendHeaders();						
			//3发送响应正文(浏览器实际请求的资源)
			sendContent();
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	/**
	 * 发送状态行
	 */
	private void sendStatusLine() {
		try {
			System.out.println("HttpResponse:开始发送状态行...");
			//  HTTP/1.1 200 OK
			String line = "HTTP/1.1"+" "+statusCode+" "+statusReason;
			System.out.println("状态行:"+line);
			out.write(line.getBytes("ISO8859-1"));
			out.write(CR);//write CR
			out.write(LF);//write LF
			System.out.println("HttpResponse:状态行发送完毕!");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	/**
	 * 发送响应头
	 */
	private void sendHeaders() {
		try {
			System.out.println("HttpResponse:开始发送响应头...");
			//遍历headers，将每一个响应头发送给客户端
			Set<Entry<String,String>> entrySet = headers.entrySet();
			for(Entry<String,String> e : entrySet) {
				String key = e.getKey();//响应头的名字       Content-Type
				String value = e.getValue();//响应头的值   text/html
				//Content-Type: text/html
				String line = key + ": " +value;
				System.out.println("响应头:"+line);
				out.write(line.getBytes("ISO8859-1"));
				out.write(CR);
				out.write(LF);
			}
			
			//单独发送CRLF表示响应头发送完毕
			out.write(CR);//write CR
			out.write(LF);//write LF
			System.out.println("HttpResponse:响应头发送完毕!");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	/**
	 * 发送响应正文
	 */
	private void sendContent() {
		//如果正文对应的字节数组有数据，就将这组字节作为正文内容发送给客户端
		if(content != null) {
			try {
				out.write(content);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}else if(entity!=null) {//否则如果文件有，则读取文件中的字节作为正文发送
			try (
				FileInputStream fis = new FileInputStream(entity);
			){
				System.out.println("HttpResponse:开始发送响应正文...");
				//将其请求的资源所有字节作为正文发送回去			
				byte[] data = new byte[1024*10];
				int len = 0;
				while((len = fis.read(data))!=-1) {
					out.write(data,0,len);
				}
				System.out.println("HttpResponse:响应正文发送完毕!");
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	
	
	public File getEntity() {
		return entity;
	}

	public void setEntity(File entity) {
		this.entity = entity;
		//根据正文的文件设置对应的两个响应头Content-Type和Content-Length
		String fileName = entity.getName();
		System.out.println("资源的文件名:"+fileName+"!!!!!!!!!!!!!");
		//获取该文件的后缀名(文件名最后一个点之后的内容)
		String ext = fileName.substring(fileName.lastIndexOf(".")+1);
		System.out.println("资源的后缀名:"+ext+"!!!!!!!!!!!!!");

		String mimeType = getMimeType(ext);
		//设置用于说明正文内容的响应头
		setHeader("Content-Type", mimeType);
		setHeader("Content-Length", entity.length()+"");
	}

	public int getStatusCode() {
		return statusCode;
	}

	public void setStatusCode(int statusCode) {
		this.statusCode = statusCode;
	}

	public String getStatusReason() {
		return statusReason;
	}

	public void setStatusReason(String statusReason) {
		this.statusReason = statusReason;
	}
	/**
	 * 向当前响应对象中添加一个响应头
	 * @param name  响应头的名字
	 * @param value 响应头对应的值
	 */
	public void setHeader(String name,String value) {
		headers.put(name, value);
	}

	public byte[] getContent() {
		return content;
	}

	public void setContent(byte[] content) {
		this.content = content;
		//根据该字节数组长度设置响应头Content-Length
		setHeader("Content-Length", content.length+"");
	}
	
	
}	















